<?php

namespace common\traits;

use Yii;
use ReflectionClass;
use yii\helpers\Inflector;
use common\helpers\ArrayHelper;
use yii\base\InvalidParamException;

/**
 * 模型Handles操作Trait
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
trait HandlesTrait {

    /**
     * 属性额外配置信息
     * @return array
     */
    public function attributeOptions() {
        return [];
    }

    /**
     * 获取属性额外配置
     * @param string $attribute 属性标签
     * @return array
     */
    public function getAttributeOption($attribute) {
        $options = $this->attributeOptions();
        if (isset($options[$attribute])) {
            return $options[$attribute];
        } elseif (strpos($attribute, '.')) {
            $attributeParts = explode('.', $attribute);
            $neededAttribute = array_pop($attributeParts);
            $relatedModel = $this;
            foreach ($attributeParts as $relationName) {
                if ($relatedModel->isRelationPopulated($relationName) && $relatedModel->$relationName instanceof self) {
                    $relatedModel = $relatedModel->$relationName;
                } else {
                    try {
                        $relation = $relatedModel->getRelation($relationName);
                    } catch (InvalidParamException $e) {
                        return [];
                    }
                    /* @var $modelClass ActiveRecordInterface */
                    $modelClass = $relation->modelClass;
                    $relatedModel = $modelClass::instance();
                }
            }

            $options = $relatedModel->attributeOptions();
            if (isset($options[$neededAttribute])) {
                return $options[$neededAttribute];
            }
        }
        return [];
    }

    /**
     * 当前模型类可执行操作
     * @return array
     */
    public function getHandles() {
        $currentMethodName = str_replace(__CLASS__ . '::', '', __METHOD__);
        $ref = new ReflectionClass(__CLASS__);
        $handleActions = array_filter($ref->getMethods(), function($property) use ($currentMethodName) {
            if ($property->class !== __CLASS__) {
                return false;
            }
            if ($property->name === $currentMethodName) {
                return false;
            }
            if (strpos($property->name, 'getCan') !== 0) {
                return false;
            }
            return true;
        });
        $handles = [];
        foreach ($handleActions as $action) {
            if (!$this->{$action->name}()) {
                continue;
            }
            $propertyName = lcfirst(str_replace('getCan', '', $action->name));
            $name = Inflector::underscore($propertyName);
            $text = $this->getAttributeLabel($propertyName);
            $handleAction = compact('name', 'text');
            $option = $this->getAttributeOption($propertyName);
            if (!empty($option) && is_array($option)) {
                $handles[] = ArrayHelper::merge($option, $handleAction);
            } else {
                $handles[] = $handleAction;
            }
        }
        return $handles;
    }

}
